#pragma once
#include "HashTableList.h"

// A HashTable class featuring a HashTableList as the bucket type
// This class also uses the JSW hash algorithm for the HashTableList,
// thus achieving a very high lookup speed.
template <class Value>
class HashTableHash : public HashTableBase<Value, HashTableList<Value>>
{
public:
	HashTableHash(int i_Buckets = 1000);
	HashTableHash(HashClass &i_HashClass, int i_Buckets = 1000);

	bool Add(char *i_Key, Value *i_Value);
	bool Remove(char *i_Key);
	HashTableEntry<Value> *GetEntry(char *i_Key, int i_Index = -1) const;

private:
	static JswHashClass s_JswHashClass;
};

template <class Value>
bool HashTableHash<Value>::Add(char *i_Key, Value *i_Value)
{
	bool result = true;
	int index = this->GetIndex(i_Key);
	HashTableList<Value> *&bucket = this->m_Buckets[index];

	if (!bucket)
	{
		bucket = new HashTableList<Value>(this->s_JswHashClass, 100);
	}
	else
	{
		result = (this->GetEntry(i_Key, index) == NULL);
	}

	if (result)
	{
		result = bucket->Add(i_Key, i_Value);
		if (result)
		{
			this->m_ItemCount++;
		}
	}

	return result;
}

template <class Value>
bool HashTableHash<Value>::Remove(char *i_Key)
{
	int index = this->GetIndex(i_Key);
	HashTableList<Value> *&bucket = this->m_Buckets[index];
	bool result = (bucket) ? bucket->Remove(i_Key) : false;

	if (result)
	{
		this->m_ItemCount--;
		if (bucket->GetItemCount() == 0)
		{
			delete bucket;
			bucket = NULL;
		}
	}

	return result;
}

template <class Value>
HashTableEntry<Value> *HashTableHash<Value>::GetEntry(char *i_Key, int i_Index) const
{
	int index = (i_Index < 0) ? this->GetIndex(i_Key) : i_Index;
	HashTableList<Value> *bucket = this->m_Buckets[index];
	HashTableEntry<Value> *existingEntry = (bucket) ? bucket->GetEntry(i_Key) : NULL;

	return existingEntry;
}

template <class Value>
HashTableHash<Value>::HashTableHash(HashClass &i_HashClass, int i_Buckets)
	: HashTableBase(i_HashClass, i_Buckets)
{
	this->EnableAutoFreeMemory(true);
}

template <class Value>
HashTableHash<Value>::HashTableHash(int i_Buckets)
	: HashTableBase(i_Buckets)
{
	this->EnableAutoFreeMemory(true);
}

template <class Value>
JswHashClass HashTableHash<Value>::s_JswHashClass;